/**
 * 
 */
package cz.cvut.fit.crhonjar.mi.run.hawera.tree.expression;

import java.util.List;

import cz.cvut.fit.crhonjar.mi.run.hawera.tree.TreeVisitor;

/**
 * @author Jarec
 * 
 */
public class FunctionCallTree extends ExpressionTree {

	private String name;
	private boolean function;
	private boolean constant;
	private List<ExpressionTree> parameters;
	private FunctionCallTree nested;

	/**
	 * constructor for simple identifier
	 * 
	 * @param name
	 * @param nested
	 */
	public FunctionCallTree(String name, FunctionCallTree nested) {
		super();
		this.log.debug("> FunctionCallTree name: {}", name);
		if ((name == null) || (name.trim().length() == 0)) {
			this.log.error("Name for function or identifier is NULL!");
			throw new NullPointerException("");
		}
		this.name = name.trim();
		this.function = false;
		this.parameters = null;
		this.nested = nested;
		if (this.name.toUpperCase().equals(name) && (this.nested == null)) {
			this.constant = true;
		}
		this.log.debug("< FuntionCallTree isFuntion: false");
	}

	/**
	 * constructor for function identifier
	 * 
	 * @param name
	 * @param parameters
	 * @param nested
	 */
	public FunctionCallTree(String name, List<ExpressionTree> parameters,
			FunctionCallTree nested) {
		super();
		this.log.debug("> FunctionCallTree name: {}", name);
		if ((name == null) || (name.trim().length() == 0)) {
			this.log.error("Name for function or identifier is NULL!");
			throw new NullPointerException("");
		}
		this.name = name.trim();

		if (parameters == null) {
			this.function = false;
		} else {
			this.function = true;
		}
		this.parameters = parameters;
		this.nested = nested;
		this.constant = false;
		this.log.debug("< FuntionCallTree isFuntion {}, isConstant: {}",
				this.isFunction(), this.isConstant());
	}

	/*
	 * 
	 * @see
	 * cz.cvut.fit.crhonjar.mi.run.hawera.tree.Tree#accept(cz.cvut.fit.crhonjar
	 * .mi.run.hawera.tree.TreeVisitor)
	 */
	@Override
	public void accept(TreeVisitor visitor) {
		visitor.visitIdentifier(this);

	}

	@Override
	public boolean evaluableAtCompileTime() {
		this.log.debug(">< evaluableAtCompileTime result: false");
		return false;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		this.log.debug(">< getName result: {}", this.name);
		return this.name;
	}

	/**
	 * @return the nested
	 */
	public FunctionCallTree getNested() {
		this.log.debug(">< getNested isNested?: {}", this.isNested());
		return this.nested;
	}

	/**
	 * @return the parameters
	 */
	public List<ExpressionTree> getParameters() {
		this.log.debug(">< getParameters exists?: {}", this.parameters != null);
		return this.parameters;
	}

	@Override
	public ExpressionType getType() {
		this.log.debug(">< getType result: {}", ExpressionType.OBJECT);
		return ExpressionType.OBJECT;
	}

	/**
	 * @return the constant
	 */
	public boolean isConstant() {
		this.log.debug("> isConstant");
		if (this.constant) {
			log.debug("< isConstant result: true");
			return true;
		}
		if (!this.isFunction()) {
			return this.nested.isConstant();
		}
		this.log.debug("< isConstant result: false");
		return false;
	}

	/**
	 * @return the function
	 */
	public boolean isFunction() {
		this.log.debug(">< isFunction result: {}", this.function);
		return this.function;
	}

	/**
	 * is FunctionCall nested?
	 * 
	 * @return
	 */
	public boolean isNested() {
		boolean isNested = !(this.nested == null);
		this.log.debug(">< isNested result: {}", isNested);
		return isNested;
	}

}
